//!
/**
 ***********************************************************************************************************
 * <RBD3D9Tools Implementation>
 ***********************************************************************************************************
 * @file RBD3D9Tools.cpp
 ***********************************************************************************************************/

/***********************************************************************************************************
 * Precompiled Header
 ***********************************************************************************************************/
#include "RBD3D9RendererPCH.h"

/***********************************************************************************************************
 * Includes
 ***********************************************************************************************************/
#include "RBD3D9Tools.h"

#include <RBMain/RBHardwareBuffer.h>
#include <RBMain/RBPixelBuffer.h>
#include <RBMain/RBTransform.h>
#include <RBMain/RBVector.h>

/***********************************************************************************************************
 * Defines
 ***********************************************************************************************************/

/***********************************************************************************************************
 * Classes implementation
 ***********************************************************************************************************/

namespace RBD3D9Tools
{

/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
void ComputeD3DTransposeFromRB(D3DXMATRIX& d3dOut, const float4x4& rbIn)
{
    d3dOut._11 = rbIn(0,0);     d3dOut._12 = rbIn(0,1);     d3dOut._13 = rbIn(0,2);     d3dOut._14 = rbIn(0,3);
    d3dOut._21 = rbIn(1,0);     d3dOut._22 = rbIn(1,1);     d3dOut._23 = rbIn(1,2);     d3dOut._24 = rbIn(1,3);
    d3dOut._31 = rbIn(2,0);     d3dOut._32 = rbIn(2,1);     d3dOut._33 = rbIn(2,2);     d3dOut._34 = rbIn(2,3);
    d3dOut._41 = rbIn(3,0);     d3dOut._42 = rbIn(3,1);     d3dOut._43 = rbIn(3,2);     d3dOut._44 = rbIn(3,3);

}

/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
void ComputeD3DFromRB(D3DXMATRIX& d3dOut, const float4x4& rbIn)
{
    d3dOut._11 = rbIn(0,0);     d3dOut._12 = rbIn(1,0);     d3dOut._13 = rbIn(2,0);     d3dOut._14 = rbIn(3,0);
    d3dOut._21 = rbIn(0,1);     d3dOut._22 = rbIn(1,1);     d3dOut._23 = rbIn(2,1);     d3dOut._24 = rbIn(3,1);
    d3dOut._31 = rbIn(0,2);     d3dOut._32 = rbIn(1,2);     d3dOut._33 = rbIn(2,2);     d3dOut._34 = rbIn(3,2);
    d3dOut._41 = rbIn(0,3);     d3dOut._42 = rbIn(1,3);     d3dOut._43 = rbIn(2,3);     d3dOut._44 = rbIn(3,3);
}

/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
void ComputeD3DFromRB(D3DXMATRIX& d3dOut, const RBTransform& rbIn)
{
    d3dOut._11 = rbIn.Rotate(0,0);      d3dOut._12 = rbIn.Rotate(1,0);     d3dOut._13 = rbIn.Rotate(2,0);     d3dOut._14 = 0;
    d3dOut._21 = rbIn.Rotate(0,1);      d3dOut._22 = rbIn.Rotate(1,1);     d3dOut._23 = rbIn.Rotate(2,1);     d3dOut._24 = 0;
    d3dOut._31 = rbIn.Rotate(0,2);      d3dOut._32 = rbIn.Rotate(1,2);     d3dOut._33 = rbIn.Rotate(2,2);     d3dOut._34 = 0;
    d3dOut._41 = rbIn.Translate.x;    d3dOut._42 = rbIn.Translate.y;   d3dOut._43 = rbIn.Translate.z;   d3dOut._44 = 1;
}

/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
DWORD ComputeD3DUsageFromRB(uint32 rbHardwareBufferUsage)
{
    DWORD dwUsage = 0;
    if (rbHardwareBufferUsage & (RBHardwareBuffer::HBU_CPUREAD | RBHardwareBuffer::HBU_CPUWRITE))
    {
        // We allow locking buffer to CPU: put dynamic usage
        dwUsage |= D3DUSAGE_DYNAMIC;
    }
    if ((rbHardwareBufferUsage & RBHardwareBuffer::HBU_CPUREAD) == 0)
    {
        // We guarantee that the Buffer will never be read back from GPU
        dwUsage |= D3DUSAGE_WRITEONLY;
    }
    if (rbHardwareBufferUsage & RBHardwareBuffer::HBU_GPUWRITE)
    {
        // We are writing to the resource with the GPU -> RTT
        dwUsage |= D3DUSAGE_RENDERTARGET;
    }
    if (rbHardwareBufferUsage & RBHardwareBuffer::HBU_DEPTHSTENCIL)
    {
        dwUsage |= D3DUSAGE_DEPTHSTENCIL;
    }

#pragma TODO("deal with textures")

    return dwUsage;
}

/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
DWORD ComputeD3DMapFlagsFromRB(const RBHardwareBuffer::MapType& eMapType, RBHardwareBuffer* pBuffer)
{
    DWORD d3dMapFlags = /*(mapOptions.m_bDoNotWait) ? D3DLOCK_DONOTWAIT :*/ 0;
    switch(eMapType)
    {
    case RBHardwareBuffer::HBM_READ_ONLY:
        d3dMapFlags  |= (pBuffer->GetUsage() & RBHardwareBuffer::HBU_CPUREAD) ? D3DLOCK_READONLY : 0;
        break;
    case RBHardwareBuffer::HBM_WRITE_ONLY:
        d3dMapFlags  |= (pBuffer->GetUsage() & RBHardwareBuffer::HBU_CPUWRITE) ? D3DLOCK_DISCARD : 0;
        break;
    case RBHardwareBuffer::HBM_READ_WRITE:
        break;
    case RBHardwareBuffer::HBM_WRITE_DISCARD:
        d3dMapFlags |= (pBuffer->GetUsage() & RBHardwareBuffer::HBU_CPUWRITE) ? D3DLOCK_DISCARD : 0;
        break;
    case RBHardwareBuffer::HBM_WRITE_NO_OVERWRITE:
        d3dMapFlags  |= (pBuffer->GetUsage() & RBHardwareBuffer::HBU_CPUWRITE) ? D3DLOCK_NOOVERWRITE : 0;
        break;
    default:
        break;
    }

    return d3dMapFlags;

}

#define RBTF_TO_D3DFMT(name) PF_##name = D3DFMT_##name

static D3DFORMAT g_aD3DFormat[PF_COUNT] = 
{
    D3DFMT_UNKNOWN,
    D3DFMT_R8G8B8,
    D3DFMT_A8R8G8B8,
    D3DFMT_X8R8G8B8,
    D3DFMT_R5G6B5,
    D3DFMT_X1R5G5B5,
    D3DFMT_A1R5G5B5,
    D3DFMT_A4R4G4B4,
    D3DFMT_R3G3B2,
    D3DFMT_A8,
    D3DFMT_A8R3G3B2,
    D3DFMT_X4R4G4B4,
    D3DFMT_A2B10G10R10,
    D3DFMT_A8B8G8R8,
    D3DFMT_X8B8G8R8,
    D3DFMT_G16R16,
    D3DFMT_A2R10G10B10,
    D3DFMT_A16B16G16R16,
    D3DFMT_A8P8,
    D3DFMT_P8,
    D3DFMT_L8,
    D3DFMT_A8L8,
    D3DFMT_A4L4,
    D3DFMT_V8U8,
    D3DFMT_L6V5U5,
    D3DFMT_X8L8V8U8,
    D3DFMT_Q8W8V8U8,
    D3DFMT_V16U16,
    D3DFMT_A2W10V10U10,
    D3DFMT_UYVY,
    D3DFMT_R8G8_B8G8,
    D3DFMT_YUY2,
    D3DFMT_G8R8_G8B8,
    D3DFMT_DXT1,
    D3DFMT_DXT2,
    D3DFMT_DXT3,
    D3DFMT_DXT4,
    D3DFMT_DXT5,
    D3DFMT_D16_LOCKABLE,
    D3DFMT_D32,
    D3DFMT_D15S1,
    D3DFMT_D24S8,
    D3DFMT_D24X8,
    D3DFMT_D24X4S4,
    D3DFMT_D16,
    D3DFMT_R16F,
    D3DFMT_G16R16F,
    D3DFMT_A16B16G16R16F,
    D3DFMT_R32F,
    D3DFMT_G32R32F,
    D3DFMT_A32B32G32R32F,
    (D3DFORMAT)MAKEFOURCC('D','F','1','6'),
    (D3DFORMAT)MAKEFOURCC('D','F','2','4'),
};

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
D3DFORMAT ComputeD3DFormat(RBPixelFormat ePixelFormat)
{
    return g_aD3DFormat[ePixelFormat];
}

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
void ComputeD3DMSAA(uint32 uiMSAA, D3DMULTISAMPLE_TYPE& d3dMS, DWORD& d3dMSQuality)
{
    UNUSED(uiMSAA);

    if (uiMSAA & RBPixelBuffer::MS_NONMASKABLE)
    {
        d3dMS = D3DMULTISAMPLE_NONMASKABLE;
        d3dMSQuality = (uiMSAA & ~((uint32)RBPixelBuffer::MS_NONMASKABLE));
    }
    else
    {
        d3dMS = (D3DMULTISAMPLE_TYPE)uiMSAA;
        d3dMSQuality = 0;
    }
}

D3DPOOL ComputeD3DPool( RBHardwareBuffer::MemPool eMemPool )
{
    switch(eMemPool)
    {
    case RBHardwareBuffer::MP_CPU:
        return D3DPOOL_SYSTEMMEM;
    default:
        break;
    }

    return D3DPOOL_DEFAULT;

}

}

/***********************************************************************************************************/
